package com.caocaog.market.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.caocaog.market.entity.ShopDelivery;
import com.caocaog.market.entity.ShopDeliveryHis;
import com.caocaog.market.entity.ShopKilometerPrice;
import com.caocaog.market.mapper.ShopDeliveryMapper;
import com.caocaog.market.service.ShopDeliveryHisService;
import com.caocaog.market.service.ShopDeliveryService;
import com.caocaog.market.service.ShopKilometerPriceService;
import com.caocaog.market.vo.ShopDeliveryVO;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.exception.CheckFailedException;
import org.jeecg.common.exception.JeecgBootException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 店铺配送管理
 *
 * @author chechen
 * @date 2021-11-30
 */
@Service
@Transactional
@RequiredArgsConstructor
public class ShopDeliveryServiceImpl extends ServiceImpl<ShopDeliveryMapper, ShopDelivery> implements ShopDeliveryService {

    private final ShopKilometerPriceService kilometerPriceService;
    private final ShopDeliveryHisService shopDeliveryHisService;

    @Override
    public ShopDeliveryVO queryShopDeliveryByShopId(String shopId) {
        ShopDelivery shopDelivery = this.selectByShopId(shopId);
        if (shopDelivery == null)
            return null;
        return this.handleDeliveryToVO(shopDelivery);
    }

    private ShopDeliveryVO handleDeliveryToVO(ShopDelivery shopDelivery) {
        ShopDeliveryVO shopDeliveryVO = new ShopDeliveryVO();
        if (shopDelivery == null || shopDelivery.getShopId() == null)
            return shopDeliveryVO;
        shopDeliveryVO.setShopDelivery(shopDelivery);
        if (shopDelivery.getIntervalRange() != null && shopDelivery.getIntervalRange().length() > 0)
            shopDeliveryVO.setInterval(Arrays.stream(shopDelivery.getIntervalRange().split(","))
                    .map(this.kilometerPriceService::queryShopKilometerPriceById)
                    .sorted(Comparator.comparing(ShopKilometerPrice::getKilometerStr))
                    .collect(Collectors.toList()));
        else shopDeliveryVO.setInterval(Collections.emptyList());
        return shopDeliveryVO;
    }

    @Override
    public String addShopDelivery(ShopDeliveryVO shopDeliveryVO) {
        ShopDelivery shopDelivery = shopDeliveryVO.toShopDelivery();
        if (shopDeliveryVO.getInterval() != null && shopDeliveryVO.getInterval().size() > 0) {
            shopDelivery.setIntervalRange(StringUtils.join(
                    this.kilometerPriceService.addBatchShopKilometerPrice(shopDeliveryVO.getInterval())
                            .stream()
                            .map(ShopKilometerPrice::getId)
                            .collect(Collectors.toSet())
                    , ","));
        }
        shopDelivery.setLockVersion(1);

        int insertRecordCount = super.baseMapper.insert(shopDelivery);
        if (insertRecordCount == 0)
            throw new JeecgBootException("店铺配送新增失败");
        this.shopDeliveryHisService.addShopDeliveryHis(new ShopDeliveryHis(shopDelivery));

        return shopDelivery.getShopId();
    }

    // 测试多线程批量插入
    /*@Override
    public Boolean addBatchShopDelivery(List<ShopDeliveryVO> shopDeliveryVOs) {
        //开启一个线程池，3个线程
        ExecutorService executor = Executors.newFixedThreadPool(3);
        //计数器，初始为需要插入的数据集的条数
        CountDownLatch countDownLatch = new CountDownLatch(shopDeliveryVOs.size());
        int i = 0;
        //出现异常返回
        final int[] flag = {0};
        int t = 0;
        try {
            //每条数据都写进去
            for (; i < shopDeliveryVOs.size(); i++) {
                int index = i;
                executor.execute(() -> {
                    try {
                        //插入业务 略
                        super.baseMapper.insert(shopDelivery);
                    } catch (Exception e) {
                        //写入日志
                        log.error("第" + index + "条出错  " + e.getMessage());
                        //修改异常标志
                        flag[0] = 1;
                        throw new RuntimeException("第" + index + "条出错  ");
                    } finally {
                        //计数器减一
                        countDownLatch.countDown();
                    }
                });
            }
            //如果计数器不为0，就等待，这个如果计数不正确，主线程就会先执行，相当于数据还没有插完，就返回成功给前端.
            countDownLatch.await();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭线程池
            executor.shutdown();
        }
        return flag[0] != 1;
    }*/

    @Override
    public void updateShopDelivery(ShopDeliveryVO shopDeliveryVO) {
        // 把数据库里的数据查出来
        ShopDeliveryVO shopDeliveryVOByDB = this.queryShopDeliveryByShopId(shopDeliveryVO.getShopId());
        ShopDelivery shopDelivery = shopDeliveryVO.toShopDelivery();
        // 根据前台传来的区间，和数据库里的区间进行对比，查看哪些进行了更改
        List<ShopKilometerPrice> finalHandle = new ArrayList<>();

        // 先获取前台传来的区间 与数据库里的区间 它们的交集（交集是这次更新不需要更改的地方）
        List<ShopKilometerPrice> intersect = shopDeliveryVOByDB.getInterval()
                .stream()
                .filter(shopDeliveryVO.getInterval()::contains)
                .collect(Collectors.toList());
        // 前端传来的 - 交集 = 数据库里没有的 （这是求差集，求出来的是需要新插入到数据库的）
        List<ShopKilometerPrice> except = shopDeliveryVO.getInterval()
                .stream()
                .filter(item -> !intersect.contains(item))
                .collect(Collectors.toList());
        this.kilometerPriceService.addBatchShopKilometerPrice(except);

        finalHandle.addAll(intersect);
        finalHandle.addAll(except);
        // 最后排个序，把id提取出来，再插入
        shopDelivery.setIntervalRange(StringUtils.join(finalHandle.stream()
                .sorted(Comparator.comparing(ShopKilometerPrice::getKilometerStr))
                .map(ShopKilometerPrice::getId)
                .collect(Collectors.toList()), ","
        ));

        super.baseMapper.updateById(shopDelivery);
        if (shopDelivery.getShopId() == null)
            throw new JeecgBootException("更新店铺配送管理失败, id-> " + shopDeliveryVO.getShopId());
        // 最后的最后插入历史表
        this.shopDeliveryHisService.addShopDeliveryHis(new ShopDeliveryHis(shopDelivery));
    }

    @Override
    public int deleteShopDelivery(Long id) {
        // 先查出数据库的
        ShopDelivery shopDelivery = this.selectByShopId(id.toString());
        if (shopDelivery == null) {
            throw new CheckFailedException("未找到相应店铺配送管理信息, shopId-> " + id);
        }
        List<String> toBeDeletedIds = Arrays.asList(shopDelivery.getIntervalRange().split(","));

        this.kilometerPriceService.deleteBatchShopKilometerPrice(toBeDeletedIds);
        int deleteRecordCount = super.baseMapper.deleteById(id);
        if (deleteRecordCount == 0)
            throw new JeecgBootException("删除店铺配送管理失败, id-> " + id);
        return deleteRecordCount;
    }

    @Override
    public int deleteBatchShopDelivery(List<String> ids) {
        List<String> allToBeDeletedIds = super.baseMapper.selectList(
                        new LambdaQueryWrapper<ShopDelivery>().in(ShopDelivery::getShopId, ids))
                .stream()
                .map(item -> Arrays.asList(item.getIntervalRange().split(",")))
                .flatMap(Collection::stream).collect(Collectors.toList());
        this.kilometerPriceService.deleteBatchShopKilometerPrice(allToBeDeletedIds);
        int deleteRecordCount = super.baseMapper.deleteBatchIds(ids);
        if (deleteRecordCount < ids.size())
            throw new JeecgBootException(
                    String.format("批量删除店铺配送管理失败, deleteRecordCount-> %s, ids.size()-> %s, ids-> %s",
                            deleteRecordCount, ids.size(), ids));
        return deleteRecordCount;
    }

    private ShopDelivery selectByShopId(String shopId) {
        if (shopId == null)
            throw new CheckFailedException("店铺id（shopId）不能为空");
        return super.baseMapper.selectById(shopId);
    }

}
